﻿using System;
using System.Text;
using System.Collections.Generic;
using SdmxMl.Common;
using SdmxMl.Structure;
using SdmxMl.Manager;
using SdmxMl.GenericMetadata;


namespace SdmxMl.SanteSuisse
{
    /// <summary>
    /// Helper class to provide string values reprisenting a CATI question element
    /// </summary>
    public class CatiSilcQuestion
    {
        #region Internal Members

        private RefVarHelper varHelper;
        private AttributeValueSetType attValSet;
        private ConceptSchemeType cst;
        private ConceptType concept;
        private MultiLang varLabel;

        #endregion

        #region Construction

        public CatiSilcQuestion(RefVarHelper rvh, AttributeValueSetType at, string lg)
        {
            varHelper = rvh;
            attValSet = at;
            langCd = lg;
            UseCrLfInCode = true;
            MaxCodes = 0;

            GetSchemeInfo();
        }

        private void GetSchemeInfo()
        {
            UrnParser up = null;
            try
            {
                ReportedAttributeType repAtt = attValSet.ReportedAttributeList.GetReportedAttributeOfConcept("CONCEPT_URN");
                ReportedAttributeType repLabel = attValSet.ReportedAttributeList.GetReportedAttributeOfConcept("LABEL_OPTIONAL");
                string urn = repAtt.Value.ToString();
                up = new UrnParser(urn);

                ArtefactRefTyped art = new ArtefactRefTyped(
                    up.ArType, up.ArtefactId, up.AgencyId, up.Version);

                cst = varHelper.GetConceptScheme(art);
                if (cst != null)
                    concept = cst.ConceptList.LocateItem(up.SubTypeId) as ConceptType;

                // Var Label
                if (concept != null && repLabel.Value.IsEmpty)
                    varLabel = concept.Name.Clone();
                else
                {
                    if (repLabel.Value.IsEmpty == false)
                         varLabel = repLabel.Value.Clone();
                    else if (concept == null)
                        varLabel = new MultiLang("Unable to get concept: " + up.SubTypeId);
                }

            }
            catch (Exception ex)
            {
                throw new ApplicationException(string.Format("Unable to get concept {0} of conceptScheme {1}",
                    up == null ? "?" : up.SubTypeId, cst == null ? "?" : cst.FullIdent), ex);
            }
        }
        #endregion

        #region Codes Fetcher

        private string FillFromUrnCodelist(string UriFieldName)
        {
            StringBuilder sb = new StringBuilder(256);
            ReportedAttributeType repAtt =
                attValSet.ReportedAttributeList.GetReportedAttributeOfConcept(UriFieldName);
            string urn = repAtt.Value.ToString();
            if (urn.Length > 0)
            {
                UrnParser upCode = new UrnParser(urn);

                ArtefactRefTyped art = new ArtefactRefTyped(
                    upCode.ArType, upCode.ArtefactId, upCode.AgencyId, upCode.Version);

                CodeListType clt = null;
                try
                {
                    clt = varHelper.GetCodelist(art);
                }
                catch
                {
                    sb.Append("Unable to retrieve codelist: " + art.FullIdent);
                }

                if (clt != null)
                {
                    int count = 0;
                    foreach (CodeType c in clt.CodeList)
                    {
                        ++ count;
                        sb.Append(c.Id).Append(" - ").Append(c.Name.GetForLanguage(langCd));
                        sb.Append(UseCrLfInCode ? Environment.NewLine: "\x0a");
                        if (MaxCodes > 0 && count >= MaxCodes)
                            break;
                    }
                }
            }
            return sb.ToString();
        }
        #endregion

        #region Properties

        public string langCd { get; set; }
        public bool UseCrLfInCode { get; set; }
        public int MaxCodes { get; set; }


        public string QuestType
        {
            get { return attValSet.TargetValuesTypeList.GetComponentValue("QUEST_TYPE").SimpleValue; }
        }

        public string Deceny
        {
            get { return attValSet.TargetValuesTypeList.GetComponentValue("YEAR").SimpleValue;}
        }

        public string VarName
        {
            get {  return attValSet.TargetValuesTypeList.GetComponentValue("VARNAME").Value;}
        }

        public string VarLabel
        {
            get { return varLabel == null ? string.Empty: varLabel.GetForLanguage(langCd); }
        }

        public string WOrder
        {
             get 
            { 
                ReportedAttributeType r =  attValSet.ReportedAttributeList.GetReportedAttributeOfConcept("WORDER");
                return r == null ? string.Empty : r.Value.GetForLanguage(langCd); 
            }
        }

        public string Filter
        {
             get 
            { 
                ReportedAttributeType r =  attValSet.ReportedAttributeList.GetReportedAttributeOfConcept("FILTER");

                 if (r != null)
                     GetVarProto(r.Value.GetForLanguage(langCd)); 

                return r == null ? string.Empty : r.Value.GetForLanguage(langCd); 
            }
        }

        public string Plausi
        {
             get 
            { 
                ReportedAttributeType r =  attValSet.ReportedAttributeList.GetReportedAttributeOfConcept("PLAUSI");
                return r == null ? string.Empty : r.Value.GetForLanguage(langCd); 
            }
        }

        public string IntroQuest
        {
            get 
            { 
                ReportedAttributeType r =  attValSet.ReportedAttributeList.GetReportedAttributeOfConcept("INTRO_QUEST");
                return r == null ? string.Empty : r.Value.GetForLanguage(langCd); 
            }
        }
        public string Question
        {
            get 
            { 
                ReportedAttributeType r =  attValSet.ReportedAttributeList.GetReportedAttributeOfConcept("QUESTION");
                return r == null ? string.Empty : r.Value.GetForLanguage(langCd); 
            }
        }
        public string InfoInterwiewer
        {
            get 
            { 
                ReportedAttributeType r =  attValSet.ReportedAttributeList.GetReportedAttributeOfConcept("INFO_INT");
                return r == null ? string.Empty : r.Value.GetForLanguage(langCd); 
            }
        }
        public string SubQuest
        {
            get 
            { 
                ReportedAttributeType r =  attValSet.ReportedAttributeList.GetReportedAttributeOfConcept("SUB_QUEST");
                return r == null ? string.Empty : r.Value.GetForLanguage(langCd); 
            }
        }

        public string QualityCodes
        {
            get { return FillFromUrnCodelist("QUALITY_URN"); }
        }

        public string VarCodes
        {
            get { return FillFromUrnCodelist("CODELIST_URN"); }
        }

        public string ConceptRef
        {
            get 
            { 
                ReportedAttributeType r =  attValSet.ReportedAttributeList.GetReportedAttributeOfConcept("CONCEPT_URN");
                return r == null ? string.Empty : r.Value.GetForLanguage(langCd);
            }
        }


        #endregion

        #region Tooltip for Var in formula

        public string VarTooltipForFormula(SmManager sm, string textVithVar)
        {
            ArtefactManager arm = sm.GetArtefactManager(SdmxArtefactType.Concepts);
            if (arm != null && arm.ArtefactList.Count > 0)
            {
                Dictionary<string, object> dico = GetVarProto(textVithVar);
                foreach (string varProto in dico.Keys)
                {
                    string conceptId = varProto.Replace("$$", "");
                    foreach (ConceptSchemeType cst in arm.ArtefactList)
                    {
                        ISdmxHierarchyListItem item = cst.ConceptList.LocateItem(conceptId);
                        if (item != null)
                        {
                            textVithVar = textVithVar.Replace(varProto, 
                                string.Format("<a title=\"{0}\" href='{2}'>{1}</a>", 
                                item.Name.ToString(), varProto, 
                                UrnManager.FullIdToUrn(SdmxArtefactType.Concepts, cst.FullIdent, item, null)));
                            break;
                        }
                    }
                }
            }
            return textVithVar;
        }

        private Dictionary<string, object> GetVarProto(string text)
        {
            Dictionary<string, object> dico = new Dictionary<string, object>();

            int index = 0;
            int n = 0;
            while ((n = text.IndexOf("$$")) > 0)
            {
                string var = string.Empty;
                index = ExtractVar(n, text, ref var);
                text = text.Substring(Math.Min(index, text.Length-1));
                if (dico.ContainsKey(var) == false)
                    dico.Add(var, null);
            }


            return dico;

        }

        private int ExtractVar(int index, string varDol, ref string varName)
        {
            while (--index >= 0)
            {
                char c = varDol[index];
                if (c != '$' && c != '_' && char.IsLetterOrDigit(c) == false)
                    break;
            }
            
            int limit = varDol.Length;
            StringBuilder sb = new StringBuilder(16);
            while (++index < limit)
            {
                char c = varDol[index];
                if (c != '$' && c != '_' && char.IsLetterOrDigit(c) == false)
                    break;
                else
                    sb.Append(c);
            }
            varName = sb.ToString();
            return index;
        }
        #endregion
    }
}
